// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// +构建忽略

package main

import (
	"fmt"
)

// 笔记：
// -布尔类型占据整个寄存器。0=假，1=真。

// 后缀对各种指令的位宽度进行编码：
// None
// D（双字）=64位整数
// W（字）=32位整数
// H（半字）=16位整数
// B（字节）=8位整数
// S（单）=32位浮点
// D（双）=64位浮点
// L=64位int，当操作码以F开头时使用

const (
	riscv64REG_G    = 27
	riscv64REG_CTXT = 20
	riscv64REG_LR   = 1
	riscv64REG_SP   = 2
	riscv64REG_TP   = 4
	riscv64REG_TMP  = 31
	riscv64REG_ZERO = 0
)

func riscv64RegName(r int) string {
	switch {
	case r == riscv64REG_G:
		return "g"
	case r == riscv64REG_SP:
		return "SP"
	case 0 <= r && r <= 31:
		return fmt.Sprintf("X%d", r)
	case 32 <= r && r <= 63:
		return fmt.Sprintf("F%d", r-32)
	default:
		panic(fmt.Sprintf("unknown register %d", r))
	}
}

func init() {
	var regNamesRISCV64 []string
	var gpMask, fpMask, gpgMask, gpspMask, gpspsbMask, gpspsbgMask regMask
	regNamed := make(map[string]regMask)

	// 构建寄存器名称列表，创建适当的索引
	// gp和fp寄存器的regMask。
	// None
	// 如果指定了名称，请使用它而不是riscv reg编号。
	addreg := func(r int, name string) regMask {
		mask := regMask(1) << uint(len(regNamesRISCV64))
		if name == "" {
			name = riscv64RegName(r)
		}
		regNamesRISCV64 = append(regNamesRISCV64, name)
		regNamed[name] = mask
		return mask
	}

	// 通用寄存器。
	for r := 0; r <= 31; r++ {
		if r == riscv64REG_LR {
			// regalloc不使用LR，因此我们跳过它离开
			// 给某人的空间。
			continue
		}

		mask := addreg(r, "")

		// 将通用寄存器添加到gpMask。
		switch r {
		// 零、TP和TMP不在任何gp掩码中。
		case riscv64REG_ZERO, riscv64REG_TP, riscv64REG_TMP:
		case riscv64REG_G:
			gpgMask |= mask
			gpspsbgMask |= mask
		case riscv64REG_SP:
			gpspMask |= mask
			gpspsbMask |= mask
			gpspsbgMask |= mask
		default:
			gpMask |= mask
			gpgMask |= mask
			gpspMask |= mask
			gpspsbMask |= mask
			gpspsbgMask |= mask
		}
	}

	// 浮动指针寄存器。
	for r := 32; r <= 63; r++ {
		mask := addreg(r, "")
		fpMask |= mask
	}

	// 伪寄存器：SB
	mask := addreg(-1, "SB")
	gpspsbMask |= mask
	gpspsbgMask |= mask

	if len(regNamesRISCV64) > 64 {
		// regMask只有64位。
		panic("Too many RISCV64 registers")
	}

	regCtxt := regNamed["X20"]
	callerSave := gpMask | fpMask | regNamed["g"]

	var (
		gpstore  = regInfo{inputs: []regMask{gpspsbMask, gpspMask, 0}} // SB在第一个输入中，因此我们可以从全局加载，但不能在第二个输入中加载，以避免将SB用作临时寄存器
		gpstore0 = regInfo{inputs: []regMask{gpspsbMask}}
		gp01     = regInfo{outputs: []regMask{gpMask}}
		gp11     = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}
		gp21     = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}}
		gpload   = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}}
		gp11sb   = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}}
		gpxchg   = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}, outputs: []regMask{gpMask}}
		gpcas    = regInfo{inputs: []regMask{gpspsbgMask, gpgMask, gpgMask}, outputs: []regMask{gpMask}}
		gpatomic = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}}

		fp11    = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{fpMask}}
		fp21    = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{fpMask}}
		gpfp    = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{fpMask}}
		fpgp    = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{gpMask}}
		fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, 0}}
		fpload  = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{fpMask}}
		fp2gp   = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{gpMask}}

		call        = regInfo{clobbers: callerSave}
		callClosure = regInfo{inputs: []regMask{gpspMask, regCtxt, 0}, clobbers: callerSave}
		callInter   = regInfo{inputs: []regMask{gpMask}, clobbers: callerSave}
	)

	RISCV64ops := []opData{
		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0+arg1
		{name: "ADDI", argLength: 1, reg: gp11sb, asm: "ADDI", aux: "Int64"},  // arg0+生长素
		{name: "ADDIW", argLength: 1, reg: gp11, asm: "ADDIW", aux: "Int64"},  // arg0+auxint的32低位，符号扩展到64位
		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                    // -arg0
		{name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW"},                  // -arg0为32位，符号扩展为64位
		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                    // arg0-arg1
		{name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW"},                  // arg 0的32低位-arg 1的32低位，符号扩展到64位

		// M分机。H表示高（即，它返回
		// 结果）。U表示未签名。W表示字（即32位）。
		{name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, typ: "Int64"}, // arg0*arg1
		{name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, typ: "Int32"},
		{name: "MULH", argLength: 2, reg: gp21, asm: "MULH", commutative: true, typ: "Int64"},
		{name: "MULHU", argLength: 2, reg: gp21, asm: "MULHU", commutative: true, typ: "UInt64"},
		{name: "DIV", argLength: 2, reg: gp21, asm: "DIV", typ: "Int64"}, // arg0/arg1
		{name: "DIVU", argLength: 2, reg: gp21, asm: "DIVU", typ: "UInt64"},
		{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},
		{name: "DIVUW", argLength: 2, reg: gp21, asm: "DIVUW", typ: "UInt32"},
		{name: "REM", argLength: 2, reg: gp21, asm: "REM", typ: "Int64"}, // arg0%arg1
		{name: "REMU", argLength: 2, reg: gp21, asm: "REMU", typ: "UInt64"},
		{name: "REMW", argLength: 2, reg: gp21, asm: "REMW", typ: "Int32"},
		{name: "REMUW", argLength: 2, reg: gp21, asm: "REMUW", typ: "UInt32"},

		{name: "MOVaddr", argLength: 1, reg: gp11sb, asm: "MOV", aux: "SymOff", rematerializeable: true, symEffect: "RdWr"}, // arg0+生长素+辅助编码偏移量
		// auxint+aux==将auxint和aux中符号的偏移量（如果有）添加到有效地址

		{name: "MOVDconst", reg: gp01, asm: "MOV", typ: "UInt64", aux: "Int64", rematerializeable: true}, // 生长素

		// 加载：从arg0+auxint+aux加载<size>位并扩展到64位；arg1=mem
		{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // 8位，符号扩展
		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // 16位，符号扩展
		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // 32位，符号扩展
		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOV", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},     // 64位
		{name: "MOVBUload", argLength: 2, reg: gpload, asm: "MOVBU", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // 8位，零扩展
		{name: "MOVHUload", argLength: 2, reg: gpload, asm: "MOVHU", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // 16位，零扩展
		{name: "MOVWUload", argLength: 2, reg: gpload, asm: "MOVWU", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // 32位，零扩展

		// 存储：存储arg1到arg0中的<size>最低位+生长素+aux；arg2=mem
		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 8位
		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16位
		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32位
		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOV", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 64位

		// 存储：在arg0+生长素+aux中存储<size>为零；arg1=mem
		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 8位
		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16位
		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32位
		{name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 64位

		// 转换
		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // 从arg0移动，从字节扩展符号
		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // 从arg0开始移动，符号从一半延伸
		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // 从arg0移动，从word扩展符号
		{name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOV"},    // 从arg0移动
		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // 从arg0移动，从字节扩展为无符号
		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // 从arg0开始移动，从一半开始无符号扩展
		{name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // 从arg0移动，从word扩展为无符号

		{name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}, resultInArg0: true}, // 否，返回同一寄存器中的arg0

		// 轮班操作
		{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                 // arg0<<（aux1和63）
		{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                 // arg0>>（aux1和63），已签名
		{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                 // arg0>>（aux1&63），未签名
		{name: "SLLI", argLength: 1, reg: gp11, asm: "SLLI", aux: "Int64"}, // arg0<<生长素，移位量0-63
		{name: "SRAI", argLength: 1, reg: gp11, asm: "SRAI", aux: "Int64"}, // arg0>>生长素，有符号，移位量0-63
		{name: "SRLI", argLength: 1, reg: gp11, asm: "SRLI", aux: "Int64"}, // arg0>>生长素，无符号，移位量0-63

		// 按位运算
		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0^arg1
		{name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"},    // arg0^生长素
		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},   // arg0 | arg1
		{name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"},      // arg0 |生长素
		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0和arg1
		{name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"},    // arg0&生长素
		{name: "NOT", argLength: 1, reg: gp11, asm: "NOT"},                    // ^arg0

		// 生成布尔值
		{name: "SEQZ", argLength: 1, reg: gp11, asm: "SEQZ"},                 // arg0==0，结果为0或1
		{name: "SNEZ", argLength: 1, reg: gp11, asm: "SNEZ"},                 // arg0！=0，结果为0或1
		{name: "SLT", argLength: 2, reg: gp21, asm: "SLT"},                   // arg0<arg1，结果为0或1
		{name: "SLTI", argLength: 1, reg: gp11, asm: "SLTI", aux: "Int64"},   // arg0<生长素，结果为0或1
		{name: "SLTU", argLength: 2, reg: gp21, asm: "SLTU"},                 // arg0<arg1，无符号，结果为0或1
		{name: "SLTIU", argLength: 1, reg: gp11, asm: "SLTIU", aux: "Int64"}, // arg0<生长素，无符号，结果为0或1

		// MOVconvert在指针和整数之间进行转换。
		// 为了避免混淆GC，我们有一个特殊的op
		// （特别是堆栈映射）。它需要一个内存arg，因此
		// 获取有关GC安全点的正确顺序。
		{name: "MOVconvert", argLength: 2, reg: gp11, asm: "MOV"}, // arg0，但根据需要转换为int/ptr；arg1=mem

		// 电话
		{name: "CALLstatic", argLength: 1, reg: call, aux: "CallOff", call: true},         // 调用静态函数aux（*gc.Sym）。arg0=mem，auxint=argsize，返回mem
		{name: "CALLclosure", argLength: 3, reg: callClosure, aux: "CallOff", call: true}, // 通过闭包调用函数。arg0=codeptr，arg1=closure，arg2=mem，auxint=argsize，返回mem
		{name: "CALLinter", argLength: 2, reg: callInter, aux: "CallOff", call: true},     // 通过指针调用fn。arg0=codeptr，arg1=mem，auxint=argsize，返回mem

		// 达夫零
		// arg0=内存地址为零（在X10中，因副作用而更改）
		// arg1=mem
		// auxint=偏移到duffzero代码中以开始执行
		// X1（链接寄存器）因函数调用而更改
		// 返回mem
		{
			name:      "DUFFZERO",
			aux:       "Int64",
			argLength: 2,
			reg: regInfo{
				inputs:   []regMask{regNamed["X10"]},
				clobbers: regNamed["X1"] | regNamed["X10"],
			},
			typ:            "Mem",
			faultOnNilArg0: true,
		},

		// 复印件
		// arg0=dst内存地址（在X11中，因副作用而更改）
		// arg1=src内存地址（在X10中，因副作用而更改）
		// arg2=mem
		// auxint=要开始执行的duffcopy代码的偏移量
		// X1（链接寄存器）因函数调用而更改
		// 返回mem
		{
			name:      "DUFFCOPY",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs:   []regMask{regNamed["X11"], regNamed["X10"]},
				clobbers: regNamed["X1"] | regNamed["X10"] | regNamed["X11"],
			},
			typ:            "Mem",
			faultOnNilArg0: true,
			faultOnNilArg1: true,
		},

		// 通用移动和零

		// 一般未对齐归零
		// arg0=内存地址为零（在X5中，由于副作用而更改）
		// arg1=最后一个元素的地址为零（包括零）
		// arg2=mem
		// 生长素=元素大小
		// 返回mem
		// mov零（X5）
		// 加上$sz，X5
		// BGEU Rarg1，X5，-2（PC）
		{
			name:      "LoweredZero",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs:   []regMask{regNamed["X5"], gpMask},
				clobbers: regNamed["X5"],
			},
			typ:            "Mem",
			faultOnNilArg0: true,
		},

		// 一般不结盟运动
		// arg0=dst内存地址（在X5中，因副作用而更改）
		// arg1=src内存地址（在X6中，因副作用而更改）
		// arg2=src最后一个元素的地址（不能是X7，因为我们在使用arg2之前会对其进行删除）
		// arg3=mem
		// 生长素=排列
		// 将缓冲X7作为tmp寄存器。
		// 返回mem
		// mov（X6），X7
		// mov X7，（X5）
		// 加上$sz，X5
		// 加上$sz，X6
		// BGEU Rarg2，X5，-4（PC）
		{
			name:      "LoweredMove",
			aux:       "Int64",
			argLength: 4,
			reg: regInfo{
				inputs:   []regMask{regNamed["X5"], regNamed["X6"], gpMask &^ regNamed["X7"]},
				clobbers: regNamed["X5"] | regNamed["X6"] | regNamed["X7"],
			},
			typ:            "Mem",
			faultOnNilArg0: true,
			faultOnNilArg1: true,
		},

		// 原子负荷。
		// 从arg0加载。arg1=mem。
		// 返回<value，memory>，以便可以与其他加载一起正确排序。
		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},

		// 原子仓库。
		// 将arg1存储到*arg0。arg2=mem。返回内存。
		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},

		// 原子交换。
		// 将arg1存储到*arg0。arg2=mem。返回<old content of*arg0，memory>。
		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},

		// 原子加法。
		// *arg0+=arg1。arg2=mem。返回<新的*arg0内容，内存>。
		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},

		// 原子比较和交换。
		// arg0=指针，arg1=旧值，arg2=新值，arg3=内存。
		// 如果*arg0==arg1{
		// *arg0=arg2
		// 返回（真，内存）
		// }否则{
		// 返回（假，内存）
		// }
		// MOV$0，溃败
		// LR（Rarg0），Rtmp
		// BNE Rtmp，Rarg1，3（个人电脑）
		// SC Rarg2，（Rarg0），Rtmp
		// BNE Rtmp，零-3（PC）
		// MOV$1，溃败
		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},

		// 原子32位和/或。
		// *arg0&=（|=）arg1。arg2=mem。返回零。
		{name: "LoweredAtomicAnd32", argLength: 3, reg: gpatomic, asm: "AMOANDW", faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicOr32", argLength: 3, reg: gpatomic, asm: "AMOORW", faultOnNilArg0: true, hasSideEffects: true},

		// 降低通过率
		{name: "LoweredNilCheck", argLength: 2, faultOnNilArg0: true, nilCheck: true, reg: regInfo{inputs: []regMask{gpspMask}}}, // arg0=ptr，arg1=mem，返回void。如果ptr为零，则出现故障。
		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{regCtxt}}},                                                // 调度器仅在入口块的开始处确保

		// LoweredGetCallerSP返回当前函数调用方的SP。
		{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},

		// LoweredGetCallerPC计算其“调用者”将返回的PC。
		// 也就是说，如果f调用g“calls”getcallerpc，
		// 结果应为g将返回到的f内的PC。
		// 有关更详细的讨论，请参阅runtime/stubs.go。
		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},

		// LoweredWB调用runtime.gcWriteBarrier。arg0=destptr，arg1=srcptr，arg2=mem，aux=runtime.gcWriteBarrier
		// 如有必要，它会保存所有GP寄存器，
		// 但是击倒了RA（LR），因为这是一个电话
		// 和T6（REG_TMP）。
		{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}, clobbers: (callerSave &^ (gpMask | regNamed["g"])) | regNamed["X1"]}, clobberFlags: true, aux: "Sym", symEffect: "None"},

		// 这些函数有三个，因此它们可以有三个不同的寄存器输入。
		// 当我们检查0<=c<=cap（A），然后检查0<=b<=c（b），然后检查0<=A<=b（c），我们需要
		// 要匹配的默认寄存器，因此我们不需要不必要地复制寄存器。
		{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X7"], regNamed["X28"]}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
		{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X6"], regNamed["X7"]}}, typ: "Mem", call: true},  // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
		{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}}, typ: "Mem", call: true},  // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。

		// F延长。
		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true, typ: "Float32"},                                           // arg0+arg1
		{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS", commutative: false, typ: "Float32"},                                          // arg0-arg1
		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, typ: "Float32"},                                           // arg0*arg1
		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", commutative: false, typ: "Float32"},                                          // arg0/arg1
		{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS", typ: "Float32"},                                                            // sqrt（arg0）
		{name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS", typ: "Float32"},                                                              // -arg0
		{name: "FMVSX", argLength: 1, reg: gpfp, asm: "FMVSX", typ: "Float32"},                                                              // 将arg0重新解释为浮点
		{name: "FCVTSW", argLength: 1, reg: gpfp, asm: "FCVTSW", typ: "Float32"},                                                            // float32（arg0的低32位）
		{name: "FCVTSL", argLength: 1, reg: gpfp, asm: "FCVTSL", typ: "Float32"},                                                            // 浮动32（arg0）
		{name: "FCVTWS", argLength: 1, reg: fpgp, asm: "FCVTWS", typ: "Int32"},                                                              // int32（arg0）
		{name: "FCVTLS", argLength: 1, reg: fpgp, asm: "FCVTLS", typ: "Int64"},                                                              // int64（arg0）
		{name: "FMOVWload", argLength: 2, reg: fpload, asm: "MOVF", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // 从arg0+auxint+aux加载float32
		{name: "FMOVWstore", argLength: 3, reg: fpstore, asm: "MOVF", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 将浮动32存储到arg0+生长素+辅助
		{name: "FEQS", argLength: 2, reg: fp2gp, asm: "FEQS", commutative: true},                                                            // arg0==arg1
		{name: "FNES", argLength: 2, reg: fp2gp, asm: "FNES", commutative: true},                                                            // arg0！=arg1
		{name: "FLTS", argLength: 2, reg: fp2gp, asm: "FLTS"},                                                                               // arg0<arg1
		{name: "FLES", argLength: 2, reg: fp2gp, asm: "FLES"},                                                                               // arg0<=arg1

		// D扩展。
		{name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true, typ: "Float64"},                                           // arg0+arg1
		{name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD", commutative: false, typ: "Float64"},                                          // arg0-arg1
		{name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true, typ: "Float64"},                                           // arg0*arg1
		{name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD", commutative: false, typ: "Float64"},                                          // arg0/arg1
		{name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD", typ: "Float64"},                                                            // sqrt（arg0）
		{name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD", typ: "Float64"},                                                              // -arg0
		{name: "FMVDX", argLength: 1, reg: gpfp, asm: "FMVDX", typ: "Float64"},                                                              // 将arg0重新解释为浮点
		{name: "FCVTDW", argLength: 1, reg: gpfp, asm: "FCVTDW", typ: "Float64"},                                                            // 浮点64（arg0的低32位）
		{name: "FCVTDL", argLength: 1, reg: gpfp, asm: "FCVTDL", typ: "Float64"},                                                            // 浮动64（arg0）
		{name: "FCVTWD", argLength: 1, reg: fpgp, asm: "FCVTWD", typ: "Int32"},                                                              // int32（arg0）
		{name: "FCVTLD", argLength: 1, reg: fpgp, asm: "FCVTLD", typ: "Int64"},                                                              // int64（arg0）
		{name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", typ: "Float64"},                                                            // 浮动64（arg0）
		{name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", typ: "Float32"},                                                            // 浮动32（arg0）
		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "MOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // 从arg0+auxint+aux加载float64
		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 将浮动6存储到arg0+生长素+辅助
		{name: "FEQD", argLength: 2, reg: fp2gp, asm: "FEQD", commutative: true},                                                            // arg0==arg1
		{name: "FNED", argLength: 2, reg: fp2gp, asm: "FNED", commutative: true},                                                            // arg0！=arg1
		{name: "FLTD", argLength: 2, reg: fp2gp, asm: "FLTD"},                                                                               // arg0<arg1
		{name: "FLED", argLength: 2, reg: fp2gp, asm: "FLED"},                                                                               // arg0<=arg1
	}

	RISCV64blocks := []blockData{
		{name: "BEQ", controls: 2},
		{name: "BNE", controls: 2},
		{name: "BLT", controls: 2},
		{name: "BGE", controls: 2},
		{name: "BLTU", controls: 2},
		{name: "BGEU", controls: 2},

		{name: "BEQZ", controls: 1},
		{name: "BNEZ", controls: 1},
		{name: "BLEZ", controls: 1},
		{name: "BGEZ", controls: 1},
		{name: "BLTZ", controls: 1},
		{name: "BGTZ", controls: 1},
	}

	archs = append(archs, arch{
		name:            "RISCV64",
		pkg:             "cmd/internal/obj/riscv",
		genfile:         "../../riscv64/ssa.go",
		ops:             RISCV64ops,
		blocks:          RISCV64blocks,
		regnames:        regNamesRISCV64,
		gpregmask:       gpMask,
		fpregmask:       fpMask,
		framepointerreg: -1, // 不用
	})
}
